﻿using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.IO.Ports;
using System.IO.Pipes;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO.MemoryMappedFiles;
using System.Diagnostics;

namespace Go
{
    internal static class TypeReflection
    {
        public static readonly Assembly _systemAss = Assembly.LoadFrom(RuntimeEnvironment.GetRuntimeDirectory() + "System.dll");
        public static readonly Assembly _mscorlibAss = Assembly.LoadFrom(RuntimeEnvironment.GetRuntimeDirectory() + "mscorlib.dll");

        public static MethodInfo GetMethod(Type type, string name, Type[] parmsType = null)
        {
            MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
            for (int i = 0; i < methods.Length; i++)
            {
                if (methods[i].Name == name)
                {
                    if (null == parmsType)
                    {
                        return methods[i];
                    }
                    else
                    {
                        ParameterInfo[] parameters = methods[i].GetParameters();
                        if (parameters.Length == parmsType.Length)
                        {
                            int j = 0;
                            for (; j < parmsType.Length && parameters[j].ParameterType == parmsType[j]; j++) { }
                            if (j == parmsType.Length)
                            {
                                return methods[i];
                            }
                        }
                    }
                }
            }
            return null;
        }

        public static FieldInfo GetField(Type type, string name)
        {
            FieldInfo[] members = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
            for (int i = 0; i < members.Length; i++)
            {
                if (members[i].Name == name)
                {
                    return members[i];
                }
            }
            return null;
        }

        public static Delegate CreateNew<Delegate>(Type type, Type[] paramTypes)
        {
            var paramObjs = new ParameterExpression[paramTypes.Length];
            var fixedObjs = new ParameterExpression[paramTypes.Length];
            var exps = new List<Expression>(paramTypes.Length + 1);
            for (int i = 0; i < paramTypes.Length; i++)
            {
                paramObjs[i] = Expression.Parameter(typeof(object));
                fixedObjs[i] = Expression.Variable(paramTypes[i]);
                exps.Add(Expression.Assign(fixedObjs[i], Expression.Convert(paramObjs[i], paramTypes[i])));
            }
            var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null);
            exps.Add(Expression.New(constructor, fixedObjs));
            var newBody = Expression.Block(fixedObjs, exps);
            return Expression.Lambda<Delegate>(newBody, paramObjs).Compile();
        }

        public static Delegate CreateNew<Delegate>(Type type)
        {
            var arguments = typeof(Delegate).GetGenericArguments();
            var paramTypes = new Type[arguments.Length - 1];
            Array.Copy(arguments, 0, paramTypes, 0, paramTypes.Length);
            var paramObjs = new ParameterExpression[paramTypes.Length];
            for (int i = 0; i < paramTypes.Length; i++)
            {
                paramObjs[i] = Expression.Parameter(paramTypes[i]);
            }
            var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, paramTypes, null);
            var newBody = Expression.New(constructor, paramObjs);
            return Expression.Lambda<Delegate>(newBody, paramObjs).Compile();
        }

        public static Func<T, R> CreateObjectGetter<T, R>(string name)
        {
            var fieldInfo = GetField(typeof(T), name);
            var paramObj = Expression.Parameter(typeof(T));
            var interField = Expression.Field(paramObj, fieldInfo);
            return Expression.Lambda<Func<T, R>>(interField, paramObj).Compile();
        }

        public static Func<object, R> CreateObjectGetter<R>(Type type, string name)
        {
            var fieldInfo = GetField(type, name);
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(type);
            var cvtObj = Expression.Assign(fixedObj, Expression.Convert(paramObj, type));
            var interField = Expression.Field(cvtObj, fieldInfo);
            var getFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, new Expression[] { cvtObj, interField });
            return Expression.Lambda<Func<object, R>>(getFieldBody, paramObj).Compile();
        }

        public static Action<T, object> CreateObjectSetter<T>(string name)
        {
            var fieldInfo = GetField(typeof(T), name);
            var paramObj = Expression.Parameter(typeof(T));
            var value = Expression.Parameter(typeof(object));
            var setField = Expression.Assign(Expression.Field(paramObj, fieldInfo), Expression.Convert(value, fieldInfo.FieldType));
            return Expression.Lambda<Action<T, object>>(setField, paramObj, value).Compile();
        }

        public static Action<object, object> CreateObjectSetter(Type type, string name)
        {
            var fieldInfo = GetField(type, name);
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(type);
            var value = Expression.Parameter(typeof(object));
            var cvtObj = Expression.Assign(fixedObj, Expression.Convert(paramObj, type));
            var interField = Expression.Field(cvtObj, fieldInfo);
            var setField = Expression.Assign(interField, Expression.Convert(value, fieldInfo.FieldType));
            var setFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, new Expression[] { cvtObj, interField, setField });
            return Expression.Lambda<Action<object, object>>(setFieldBody, paramObj, value).Compile();
        }
    }

    public struct socket_result
    {
        public bool success;
        public int size;
        public System.Exception ec;

        public socket_result(bool success = false, int size = 0, System.Exception ec = null)
        {
            this.success = success;
            this.size = size;
            this.ec = ec;
        }

        public string message
        {
            get
            {
                return null != ec ? ec.Message : null;
            }
        }

        static public implicit operator bool(socket_result src)
        {
            return src.success;
        }

        static public implicit operator int(socket_result src)
        {
            return src.size;
        }
    }

    struct WSABuffer
    {
        public int Length;
        public IntPtr Pointer;
    }

    struct socket_same_handler
    {
        public GCHandle pinnedObj;
        public Action<socket_result> callback;
        public AsyncCallback handler;
    }

    struct socket_handler
    {
        public int currTotal;
        public ArraySegment<byte> buff;
        public Action<socket_result> callback;
        public Action<socket_result> handler;
    }

    struct socket_ptr_handler
    {
        public int currTotal;
        public IntPtr pointer;
        public int size;
        public GCHandle pinnedObj;
        public Action<socket_result> handler;
        public Action<socket_result> callback;
    }

    struct accept_handler
    {
        public socket_tcp socket;
        public AsyncCallback handler;
        public Action<socket_result> callback;
    }

    struct accept_lost_handler
    {
        public socket_tcp socket;
        public Action<socket_result> handler;
    }

    public abstract class socket
    {
        [DllImport("kernel32.dll")]
        static extern int WriteFile(SafeHandle handle, IntPtr bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
        [DllImport("kernel32.dll")]
        static extern int ReadFile(SafeHandle handle, IntPtr bytes, int numBytesToRead, out int numBytesRead, IntPtr mustBeZero);
        [DllImport("kernel32.dll")]
        static extern int CancelIoEx(SafeHandle handle, IntPtr mustBeZero);

        static readonly Func<UnmanagedMemoryAccessor, SafeBuffer> _getAccessorBuffer = TypeReflection.CreateObjectGetter<UnmanagedMemoryAccessor, SafeBuffer>("_buffer");
        static readonly Func<UnmanagedMemoryStream, SafeBuffer> _getStreamBuffer = TypeReflection.CreateObjectGetter<UnmanagedMemoryStream, SafeBuffer>("_buffer");
        static readonly Func<SafeHandle, IntPtr> _getSafeHandle = TypeReflection.CreateObjectGetter<SafeHandle, IntPtr>("handle");

        static public tuple<bool, int> sync_write(SafeHandle handle, IntPtr pointer, long offset, int size)
        {
            int num = 0;
            return new tuple<bool, int>(1 == WriteFile(handle, new IntPtr(pointer.ToInt64() + offset), size, out num, IntPtr.Zero), num);
        }

        static public tuple<bool, int> sync_read(SafeHandle handle, IntPtr pointer, long offset, int size)
        {
            int num = 0;
            return new tuple<bool, int>(1 == ReadFile(handle, new IntPtr(pointer.ToInt64() + offset), size, out num, IntPtr.Zero), num);
        }

        static public tuple<bool, int> sync_write(SafeHandle handle, byte[] bytes, int offset, int size)
        {
            return sync_write(handle, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), offset, size);
        }

        static public tuple<bool, int> sync_read(SafeHandle handle, byte[] bytes, int offset, int size)
        {
            return sync_read(handle, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), offset, size);
        }

        static public tuple<bool, int> sync_write(SafeHandle handle, byte[] bytes)
        {
            return sync_write(handle, bytes, 0, bytes.Length);
        }

        static public tuple<bool, int> sync_read(SafeHandle handle, byte[] bytes)
        {
            return sync_read(handle, bytes, 0, bytes.Length);
        }

        static public bool cancel_io(SafeHandle handle)
        {
            return 1 == CancelIoEx(handle, IntPtr.Zero);
        }

        static public IntPtr get_mmview_ptr(MemoryMappedViewAccessor mmv)
        {
            return _getSafeHandle(_getAccessorBuffer(mmv));
        }

        static public IntPtr get_mmview_ptr(MemoryMappedViewStream mmv)
        {
            return _getSafeHandle(_getStreamBuffer(mmv));
        }

        socket_handler _readHandler;
        socket_handler _writeHandler;

        protected socket()
        {
            _readHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _readHandler.currTotal += tempRes.size;
                    _readHandler.buff = new ArraySegment<byte>(_readHandler.buff.Array, _readHandler.buff.Offset + tempRes.size, _readHandler.buff.Count - tempRes.size);
                    if (0 == _readHandler.buff.Count)
                    {
                        Action<socket_result> callback = _readHandler.callback;
                        _readHandler.buff = default(ArraySegment<byte>);
                        _readHandler.callback = null;
                        functional.catch_invoke(callback, new socket_result(true, _readHandler.currTotal));
                    }
                    else
                    {
                        async_read_same(_readHandler.buff, _readHandler.handler);
                    }
                }
                else
                {
                    Action<socket_result> callback = _readHandler.callback;
                    _readHandler.buff = default(ArraySegment<byte>);
                    _readHandler.callback = null;
                    functional.catch_invoke(callback, new socket_result(false, _readHandler.currTotal, tempRes.ec));
                }
            };
            _writeHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _writeHandler.currTotal += tempRes.size;
                    _writeHandler.buff = new ArraySegment<byte>(_writeHandler.buff.Array, _writeHandler.buff.Offset + tempRes.size, _writeHandler.buff.Count - tempRes.size);
                    if (0 == _writeHandler.buff.Count)
                    {
                        Action<socket_result> callback = _writeHandler.callback;
                        _writeHandler.buff = default(ArraySegment<byte>);
                        _writeHandler.callback = null;
                        functional.catch_invoke(callback, new socket_result(true, _writeHandler.currTotal));
                    }
                    else
                    {
                        async_write_same(_writeHandler.buff, _writeHandler.handler);
                    }
                }
                else
                {
                    Action<socket_result> callback = _writeHandler.callback;
                    _writeHandler.buff = default(ArraySegment<byte>);
                    _writeHandler.callback = null;
                    functional.catch_invoke(callback, new socket_result(false, _writeHandler.currTotal, tempRes.ec));
                }
            };
        }

        public abstract void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback);
        public abstract void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback);
        public abstract void close();

        public void async_read_same(byte[] buff, Action<socket_result> callback)
        {
            async_read_same(new ArraySegment<byte>(buff), callback);
        }

        public void async_write_same(byte[] buff, Action<socket_result> callback)
        {
            async_write_same(new ArraySegment<byte>(buff), callback);
        }

        void _async_reads(int currTotal, int currIndex, IList<ArraySegment<byte>> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_read(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_reads(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        void _async_reads(int currTotal, int currIndex, IList<byte[]> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_read(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_reads(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        public void async_read(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            _readHandler.currTotal = 0;
            _readHandler.buff = buff;
            _readHandler.callback = callback;
            async_read_same(_readHandler.buff, _readHandler.handler);
        }

        public void async_read(byte[] buff, Action<socket_result> callback)
        {
            async_read(new ArraySegment<byte>(buff), callback);
        }

        void _async_writes(int currTotal, int currIndex, IList<ArraySegment<byte>> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_write(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_writes(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        void _async_writes(int currTotal, int currIndex, IList<byte[]> buff, Action<socket_result> callback)
        {
            if (buff.Count == currIndex)
            {
                functional.catch_invoke(callback, new socket_result(true, currTotal));
            }
            else
            {
                async_write(buff[currIndex], delegate (socket_result tempRes)
                {
                    if (tempRes.success)
                    {
                        _async_writes(currTotal + tempRes.size, currIndex + 1, buff, callback);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false, currTotal, tempRes.ec));
                    }
                });
            }
        }

        public void async_write(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            _writeHandler.currTotal = 0;
            _writeHandler.buff = buff;
            _writeHandler.callback = callback;
            async_write_same(_writeHandler.buff, _writeHandler.handler);
        }

        public void async_write(byte[] buff, Action<socket_result> callback)
        {
            async_write(new ArraySegment<byte>(buff), callback);
        }

        public ValueTask<socket_result> read_same(ArraySegment<byte> buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_read_same(buff, callback));
        }

        public ValueTask<socket_result> read_same(byte[] buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_read_same(buff, callback));
        }

        public ValueTask<socket_result> read(ArraySegment<byte> buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_read(buff, callback));
        }

        public ValueTask<socket_result> read(byte[] buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_read(buff, callback));
        }

        public ValueTask<socket_result> reads(IList<byte[]> buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public ValueTask<socket_result> reads(IList<ArraySegment<byte>> buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public ValueTask<socket_result> reads(params byte[][] buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public ValueTask<socket_result> reads(params ArraySegment<byte>[] buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public ValueTask<socket_result> write_same(ArraySegment<byte> buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_write_same(buff, callback));
        }

        public ValueTask<socket_result> write_same(byte[] buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_write_same(buff, callback));
        }

        public ValueTask<socket_result> write(ArraySegment<byte> buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_write(buff, callback));
        }

        public ValueTask<socket_result> write(byte[] buff)
        {
            return generator.async_call((Action<socket_result> callback) => async_write(buff, callback));
        }

        public ValueTask<socket_result> writes(IList<byte[]> buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public ValueTask<socket_result> writes(IList<ArraySegment<byte>> buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public ValueTask<socket_result> writes(params byte[][] buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public ValueTask<socket_result> writes(params ArraySegment<byte>[] buff)
        {
            return generator.async_call((Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public Task unsafe_read_same(async_result_wrap<socket_result> res, ArraySegment<byte> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_read_same(buff, callback));
        }

        public Task unsafe_read_same(async_result_wrap<socket_result> res, byte[] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_read_same(buff, callback));
        }

        public Task unsafe_read(async_result_wrap<socket_result> res, ArraySegment<byte> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_read(buff, callback));
        }

        public Task unsafe_read(async_result_wrap<socket_result> res, byte[] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_read(buff, callback));
        }

        public Task unsafe_reads(async_result_wrap<socket_result> res, IList<byte[]> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public Task unsafe_reads(async_result_wrap<socket_result> res, IList<ArraySegment<byte>> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public Task unsafe_reads(async_result_wrap<socket_result> res, params byte[][] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public Task unsafe_reads(async_result_wrap<socket_result> res, params ArraySegment<byte>[] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_reads(0, 0, buff, callback));
        }

        public Task unsafe_write_same(async_result_wrap<socket_result> res, ArraySegment<byte> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_write_same(buff, callback));
        }

        public Task unsafe_write_same(async_result_wrap<socket_result> res, byte[] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_write_same(buff, callback));
        }

        public Task unsafe_write(async_result_wrap<socket_result> res, ArraySegment<byte> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_write(buff, callback));
        }

        public Task unsafe_write(async_result_wrap<socket_result> res, byte[] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_write(buff, callback));
        }

        public Task unsafe_writes(async_result_wrap<socket_result> res, IList<byte[]> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public Task unsafe_writes(async_result_wrap<socket_result> res, IList<ArraySegment<byte>> buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public Task unsafe_writes(async_result_wrap<socket_result> res, params byte[][] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }

        public Task unsafe_writes(async_result_wrap<socket_result> res, params ArraySegment<byte>[] buff)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => _async_writes(0, 0, buff, callback));
        }
    }

    public class socket_tcp : socket
    {
        class SocketAsyncIo
        {
            [DllImport("Ws2_32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern SocketError WSASend(IntPtr socketHandle, ref WSABuffer buffer, int bufferCount, out int bytesTransferred, SocketFlags socketFlags, SafeHandle overlapped, IntPtr completionRoutine);
            [DllImport("Ws2_32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern SocketError WSARecv(IntPtr socketHandle, ref WSABuffer buffer, int bufferCount, out int bytesTransferred, ref SocketFlags socketFlags, SafeHandle overlapped, IntPtr completionRoutine);
            [DllImport("Kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int SetFilePointerEx(SafeHandle fileHandle, long liDistanceToMove, out long lpNewFilePointer, int dwMoveMethod);
            [DllImport("Kernel32.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int GetFileSizeEx(SafeHandle fileHandle, out long lpFileSize);
            [DllImport("Mswsock.dll", CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
            static extern int TransmitFile(IntPtr socketHandle, SafeHandle fileHandle, int nNumberOfBytesToWrite, int nNumberOfBytesPerSend, SafeHandle overlapped, IntPtr mustBeZero, int dwFlags);

            static readonly Type _overlappedType = TypeReflection._systemAss.GetType("System.Net.Sockets.OverlappedAsyncResult");
            static readonly MethodInfo _overlappedStartPostingAsyncOp = TypeReflection.GetMethod(_overlappedType, "StartPostingAsyncOp", new Type[] { typeof(bool) });
            static readonly MethodInfo _overlappedFinishPostingAsyncOp = TypeReflection.GetMethod(_overlappedType, "FinishPostingAsyncOp", new Type[] { });
            static readonly MethodInfo _overlappedSetUnmanagedStructures = TypeReflection.GetMethod(_overlappedType, "SetUnmanagedStructures", new Type[] { typeof(object) });
            static readonly MethodInfo _overlappedOverlappedHandle = TypeReflection.GetMethod(_overlappedType, "get_OverlappedHandle", new Type[] { });
            static readonly MethodInfo _overlappedCheckAsyncCallOverlappedResult = TypeReflection.GetMethod(_overlappedType, "CheckAsyncCallOverlappedResult", new Type[] { typeof(SocketError) });
            static readonly MethodInfo _sockektUpdateStatusAfterSocketError = TypeReflection.GetMethod(typeof(Socket), "UpdateStatusAfterSocketError", new Type[] { typeof(SocketError) });
            static readonly Action<Delegate, object> _setDelegateTarget = TypeReflection.CreateObjectSetter<Delegate>("_target");
            static readonly Func<Socket, object, AsyncCallback, IAsyncResult> _newOverlappedAsyncResult = TypeReflection.CreateNew<Func<Socket, object, AsyncCallback, IAsyncResult>>(_overlappedType);

            private Socket _socket;
            private AsyncCallback _callback;
            private WSABuffer _buffer;
            private Func<bool, object> _StartPostingAsyncOp;
            private Func<bool> _FinishPostingAsyncOp;
            private Action<object> _SetUnmanagedStructures;
            private Func<SafeHandle> _GetOverlappedHandle;
            private Func<SocketError, SocketError> _CheckAsyncCallOverlappedResult;

            public SocketAsyncIo(Socket socket, AsyncCallback callback)
            {
                _socket = socket;
                _callback = callback;
            }

            public SafeHandle New()
            {
                IAsyncResult asyncResult = _newOverlappedAsyncResult(_socket, null, _callback);
                if (null == _StartPostingAsyncOp)
                {
                    _StartPostingAsyncOp = (Func<bool, object>)Delegate.CreateDelegate(typeof(Func<bool, object>), asyncResult, _overlappedStartPostingAsyncOp);
                    _FinishPostingAsyncOp = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), asyncResult, _overlappedFinishPostingAsyncOp);
                    _SetUnmanagedStructures = (Action<object>)Delegate.CreateDelegate(typeof(Action<object>), asyncResult, _overlappedSetUnmanagedStructures);
                    _GetOverlappedHandle = (Func<SafeHandle>)Delegate.CreateDelegate(typeof(Func<SafeHandle>), asyncResult, _overlappedOverlappedHandle);
                    _CheckAsyncCallOverlappedResult = (Func<SocketError, SocketError>)Delegate.CreateDelegate(typeof(Func<SocketError, SocketError>), asyncResult, _overlappedCheckAsyncCallOverlappedResult);
                }
                else
                {
                    _setDelegateTarget(_StartPostingAsyncOp, asyncResult);
                    _setDelegateTarget(_FinishPostingAsyncOp, asyncResult);
                    _setDelegateTarget(_SetUnmanagedStructures, asyncResult);
                    _setDelegateTarget(_GetOverlappedHandle, asyncResult);
                    _setDelegateTarget(_CheckAsyncCallOverlappedResult, asyncResult);
                }
                _StartPostingAsyncOp(false);
                _SetUnmanagedStructures(null);
                return _GetOverlappedHandle();
            }

            public SocketError Send(IntPtr pointer, long offset, int size)
            {
                _buffer.Length = size;
                _buffer.Pointer = new IntPtr(pointer.ToInt64() + offset);
                SocketError lastWin32Error = WSASend(_socket.Handle, ref _buffer, 1, out int num, 0, New(), IntPtr.Zero);
                if (SocketError.Success != lastWin32Error)
                {
                    lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                }
                lastWin32Error = _CheckAsyncCallOverlappedResult(lastWin32Error);
                if (SocketError.Success == lastWin32Error)
                {
                    _FinishPostingAsyncOp();
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError.Invoke(_socket, new object[] { lastWin32Error });
                return lastWin32Error;
            }

            public SocketError Recv(IntPtr pointer, long offset, int size)
            {
                _buffer.Length = size;
                _buffer.Pointer = new IntPtr(pointer.ToInt64() + offset);
                SocketFlags socketFlags = 0;
                SocketError lastWin32Error = WSARecv(_socket.Handle, ref _buffer, 1, out int num, ref socketFlags, New(), IntPtr.Zero);
                if (SocketError.Success != lastWin32Error)
                {
                    lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                }
                lastWin32Error = _CheckAsyncCallOverlappedResult(lastWin32Error);
                if (SocketError.Success == lastWin32Error)
                {
                    _FinishPostingAsyncOp();
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError.Invoke(_socket, new object[] { lastWin32Error });
                return lastWin32Error;
            }

            public SocketError SendFile(SafeHandle fileHandle, long offset, int size)
            {
                if (offset >= 0)
                {
                    if (0 == SetFilePointerEx(fileHandle, offset, out long newOffset, 0) || offset != newOffset)
                    {
                        return SocketError.Fault;
                    }
                }
                SocketError lastWin32Error = SocketError.Success;
                if (0 == TransmitFile(_socket.Handle, fileHandle, size, 0, New(), IntPtr.Zero, 0x20 | 0x04))
                {
                    lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
                }
                lastWin32Error = _CheckAsyncCallOverlappedResult(lastWin32Error);
                if (SocketError.Success == lastWin32Error)
                {
                    _FinishPostingAsyncOp();
                    return SocketError.Success;
                }
                _sockektUpdateStatusAfterSocketError.Invoke(_socket, new object[] { lastWin32Error });
                return lastWin32Error;
            }
        }

        bool _closed;
        Socket _socket;
        EndPoint _localPoint;
        SocketAsyncIo _readAsyncIo;
        SocketAsyncIo _writeAsyncIo;
        socket_same_handler _readSameHandler;
        socket_same_handler _writeSameHandler;
        socket_ptr_handler _readPtrHandler;
        socket_ptr_handler _writePtrHandler;

        public socket_tcp()
        {
            _closed = false;
            _socket = null;
            _readAsyncIo = null;
            _writeAsyncIo = null;
            _readSameHandler.handler = delegate (IAsyncResult ar)
            {
                GCHandle pinnedObj = _readSameHandler.pinnedObj;
                Action<socket_result> callback = _readSameHandler.callback;
                _readSameHandler.pinnedObj = default;
                _readSameHandler.callback = null;
                try
                {
                    int size = _socket.EndReceive(ar);
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _writeSameHandler.handler = delegate (IAsyncResult ar)
            {
                GCHandle pinnedObj = _writeSameHandler.pinnedObj;
                Action<socket_result> callback = _writeSameHandler.callback;
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                try
                {
                    int size = _socket.EndSend(ar);
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _readPtrHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _readPtrHandler.currTotal += tempRes.size;
                    _readPtrHandler.pointer += tempRes.size;
                    _readPtrHandler.size -= tempRes.size;
                    if (0 == _readPtrHandler.size)
                    {
                        GCHandle pinnedObj = _readPtrHandler.pinnedObj;
                        Action<socket_result> callback = _readPtrHandler.callback;
                        _readPtrHandler.pinnedObj = default;
                        _readPtrHandler.callback = null;
                        if (pinnedObj.IsAllocated)
                        {
                            pinnedObj.Free();
                        }
                        functional.catch_invoke(callback, new socket_result(true, _readPtrHandler.currTotal));
                    }
                    else
                    {
                        async_read_same(_readPtrHandler.pointer, 0, _readPtrHandler.size, _readPtrHandler.handler);
                    }
                }
                else
                {
                    GCHandle pinnedObj = _readPtrHandler.pinnedObj;
                    Action<socket_result> callback = _readPtrHandler.callback;
                    _readPtrHandler.pinnedObj = default;
                    _readPtrHandler.callback = null;
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(false, _readPtrHandler.currTotal, tempRes.ec));
                }
            };
            _writePtrHandler.handler = delegate (socket_result tempRes)
            {
                if (tempRes.success)
                {
                    _writePtrHandler.currTotal += tempRes.size;
                    _writePtrHandler.pointer += tempRes.size;
                    _writePtrHandler.size -= tempRes.size;
                    if (0 == _writePtrHandler.size)
                    {
                        GCHandle pinnedObj = _writePtrHandler.pinnedObj;
                        Action<socket_result> callback = _writePtrHandler.callback;
                        _writePtrHandler.pinnedObj = default;
                        _writePtrHandler.callback = null;
                        if (pinnedObj.IsAllocated)
                        {
                            pinnedObj.Free();
                        }
                        functional.catch_invoke(callback, new socket_result(true, _writePtrHandler.currTotal));
                    }
                    else
                    {
                        async_write_same(_writePtrHandler.pointer, 0, _writePtrHandler.size, _writePtrHandler.handler);
                    }
                }
                else
                {
                    GCHandle pinnedObj = _writePtrHandler.pinnedObj;
                    Action<socket_result> callback = _writePtrHandler.callback;
                    _writePtrHandler.pinnedObj = default;
                    _writePtrHandler.callback = null;
                    if (pinnedObj.IsAllocated)
                    {
                        pinnedObj.Free();
                    }
                    functional.catch_invoke(callback, new socket_result(false, _writePtrHandler.currTotal, tempRes.ec));
                }
            };
        }

        public Socket socket
        {
            get
            {
                return _socket;
            }
        }

        public override void close()
        {
            try
            {
                Socket socket = null;
                lock (this)
                {
                    if (!_closed)
                    {
                        _closed = true;
                        socket = _socket;
                    }
                }
                socket?.Close();
            }
            catch (System.Exception) { }
        }

        public void bind(string ip)
        {
            _localPoint = null == ip ? null : new IPEndPoint(IPAddress.Parse(ip), 0);
        }

        public void async_connect(string ip, int port, Action<socket_result> callback)
        {
            try
            {
                bool isEmpty = false;
                lock (this) isEmpty = !_closed && null == _socket;
                if (!isEmpty)
                {
                    functional.catch_invoke(callback, new socket_result(false));
                    return;
                }
                Socket newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                if (null != _localPoint)
                {
                    newSocket.Bind(_localPoint);
                }
                newSocket.BeginConnect(IPAddress.Parse(ip), port, delegate (IAsyncResult ar)
                {
                    try
                    {
                        newSocket.EndConnect(ar);
                        newSocket.NoDelay = true;
                        bool state = false;
                        lock (this)
                        {
                            if (!_closed && null == _socket)
                            {
                                _socket = newSocket;
                                state = true;
                            }
                        }
                        if (!state)
                        {
                            newSocket.Close();
                        }
                        functional.catch_invoke(callback, new socket_result(state));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                }, null);
            }
            catch (System.Exception ec)
            {
                close();
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_disconnect(bool reuseSocket, Action<socket_result> callback)
        {
            try
            {
                _socket.BeginDisconnect(reuseSocket, delegate (IAsyncResult ar)
                {
                    try
                    {
                        _socket.EndDisconnect(ar);
                        functional.catch_invoke(callback, new socket_result(true));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                }, null);
            }
            catch (System.Exception ec)
            {
                close();
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            try
            {
                Debug.Assert(null == _readSameHandler.callback, "重入的 read 操作!");
                _readSameHandler.callback = callback;
                _socket.BeginReceive(buff.Array, buff.Offset, buff.Count, 0, _readSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            try
            {
                Debug.Assert(null == _writeSameHandler.callback, "重入的 write 操作!");
                _writeSameHandler.callback = callback;
                _socket.BeginSend(buff.Array, buff.Offset, buff.Count, 0, _writeSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_send_file(SafeHandle fileHandle, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            try
            {
                Debug.Assert(null == _writeSameHandler.callback, "重入的 write 操作!");
                _writeSameHandler.pinnedObj = pinnedObj;
                _writeSameHandler.callback = callback;
                if (null == _writeAsyncIo)
                {
                    _writeAsyncIo = new SocketAsyncIo(_socket, _writeSameHandler.handler);
                }
                SocketError lastWin32Error = _writeAsyncIo.SendFile(fileHandle, offset, size);
                if (SocketError.Success != lastWin32Error)
                {
                    throw new SocketException((int)lastWin32Error);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_read_same(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            try
            {
                Debug.Assert(null == _readSameHandler.callback, "重入的 read 操作!");
                _readSameHandler.pinnedObj = pinnedObj;
                _readSameHandler.callback = callback;
                if (null == _readAsyncIo)
                {
                    _readAsyncIo = new SocketAsyncIo(_socket, _readSameHandler.handler);
                }
                SocketError lastWin32Error = _readAsyncIo.Recv(pointer, offset, size);
                if (SocketError.Success != lastWin32Error)
                {
                    throw new SocketException((int)lastWin32Error);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.pinnedObj = default;
                _readSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_write_same(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            try
            {
                Debug.Assert(null == _writeSameHandler.callback, "重入的 write 操作!");
                _writeSameHandler.pinnedObj = pinnedObj;
                _writeSameHandler.callback = callback;
                if (null == _writeAsyncIo)
                {
                    _writeAsyncIo = new SocketAsyncIo(_socket, _writeSameHandler.handler);
                }
                SocketError lastWin32Error = _writeAsyncIo.Send(pointer, offset, size);
                if (SocketError.Success != lastWin32Error)
                {
                    throw new SocketException((int)lastWin32Error);
                }
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.pinnedObj = default;
                _writeSameHandler.callback = null;
                if (pinnedObj.IsAllocated)
                {
                    pinnedObj.Free();
                }
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void async_read(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            _readPtrHandler.currTotal = 0;
            _readPtrHandler.pointer = new IntPtr(pointer.ToInt64() + offset);
            _readPtrHandler.size = size;
            _readPtrHandler.pinnedObj = pinnedObj;
            _readPtrHandler.callback = callback;
            async_read_same(_readPtrHandler.pointer, 0, _readPtrHandler.size, _readPtrHandler.handler);
        }

        public void async_write(IntPtr pointer, long offset, int size, Action<socket_result> callback, GCHandle pinnedObj = default)
        {
            _writePtrHandler.currTotal = 0;
            _writePtrHandler.pointer = new IntPtr(pointer.ToInt64() + offset);
            _writePtrHandler.size = size;
            _writePtrHandler.pinnedObj = pinnedObj;
            _writePtrHandler.callback = callback;
            async_write_same(_writePtrHandler.pointer, 0, _writePtrHandler.size, _writePtrHandler.handler);
        }

        public ValueTask<socket_result> read_same(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.async_call((Action<socket_result> callback) => async_read_same(pointer, offset, size, callback, pinnedObj));
        }

        public ValueTask<socket_result> write_same(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.async_call((Action<socket_result> callback) => async_write_same(pointer, offset, size, callback, pinnedObj));
        }

        public ValueTask<socket_result> read(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.async_call((Action<socket_result> callback) => async_read(pointer, offset, size, callback, pinnedObj));
        }

        public ValueTask<socket_result> write(IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.async_call((Action<socket_result> callback) => async_write(pointer, offset, size, callback, pinnedObj));
        }

        public ValueTask<socket_result> send_file(SafeHandle fileHandle, long offset = 0, int size = 0, GCHandle pinnedObj = default)
        {
            return generator.async_call((Action<socket_result> callback) => async_send_file(fileHandle, offset, size, callback, pinnedObj));
        }

        public ValueTask<socket_result> connect(string ip, int port)
        {
            return generator.async_call((Action<socket_result> callback) => async_connect(ip, port, callback));
        }

        public ValueTask<socket_result> disconnect(bool reuseSocket)
        {
            return generator.async_call((Action<socket_result> callback) => async_disconnect(reuseSocket, callback));
        }

        public Task unsafe_read_same(async_result_wrap<socket_result> res, IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_read_same(pointer, offset, size, callback, pinnedObj));
        }

        public Task unsafe_write_same(async_result_wrap<socket_result> res, IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_write_same(pointer, offset, size, callback, pinnedObj));
        }

        public Task unsafe_read(async_result_wrap<socket_result> res, IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_read(pointer, offset, size, callback, pinnedObj));
        }

        public Task unsafe_write(async_result_wrap<socket_result> res, IntPtr pointer, long offset, int size, GCHandle pinnedObj = default)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_write(pointer, offset, size, callback, pinnedObj));
        }

        public Task unsafe_send_file(async_result_wrap<socket_result> res, SafeHandle fileHandle, long offset = 0, int size = 0, GCHandle pinnedObj = default)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_send_file(fileHandle, offset, size, callback, pinnedObj));
        }

        public Task unsafe_connect(async_result_wrap<socket_result> res, string ip, int port)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_connect(ip, port, callback));
        }

        public Task unsafe_disconnect(async_result_wrap<socket_result> res, bool reuseSocket)
        {
            return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_disconnect(reuseSocket, callback));
        }

        public class acceptor
        {
            Socket _socket;
            accept_handler _acceptHandler;
            accept_lost_handler _lostHandler;

            public acceptor()
            {
                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _acceptHandler.socket = null;
                _acceptHandler.callback = null;
                _acceptHandler.handler = delegate (IAsyncResult ar)
                {
                    socket_tcp socket = _acceptHandler.socket;
                    Action<socket_result> callback = _acceptHandler.callback;
                    _acceptHandler.socket = null;
                    _acceptHandler.callback = null;
                    try
                    {
                        Socket newSocket = _socket.EndAccept(ar);
                        newSocket.NoDelay = true;
                        bool state = false;
                        lock (socket)
                        {
                            if (!socket._closed && null == socket._socket)
                            {
                                socket._socket = newSocket;
                                state = true;
                            }
                        }
                        if (!state)
                        {
                            newSocket.Close();
                        }
                        functional.catch_invoke(callback, new socket_result(state));
                    }
                    catch (System.Exception ec)
                    {
                        functional.catch_invoke(callback, new socket_result(false, 0, ec));
                    }
                };
                _lostHandler.handler = delegate (socket_result res)
                {
                    _lostHandler.socket?.close();
                    _lostHandler.socket = null;
                };
            }

            public Socket socket
            {
                get
                {
                    return _socket;
                }
            }

            public bool resue
            {
                set
                {
                    try
                    {
                        _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, value);
                    }
                    catch (System.Exception) { }
                }
            }

            public bool bind(string ip, int port, int backlog = 1)
            {
                try
                {
                    _socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
                    _socket.Listen(backlog);
                    return true;
                }
                catch (System.Exception) { }
                return false;
            }

            public void close()
            {
                try
                {
                    _socket.Close();
                }
                catch (System.Exception) { }
            }

            public void async_accept(socket_tcp socket, Action<socket_result> callback)
            {
                try
                {
                    bool isEmpty;
                    lock (socket) isEmpty = !socket._closed && null == socket._socket;
                    if (isEmpty)
                    {
                        _acceptHandler.socket = socket;
                        _acceptHandler.callback = callback;
                        _socket.BeginAccept(_acceptHandler.handler, null);
                    }
                    else
                    {
                        functional.catch_invoke(callback, new socket_result(false));
                    }
                }
                catch (System.Exception ec)
                {
                    close();
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            }

            public ValueTask<socket_result> accept(socket_tcp sck)
            {
                _lostHandler.socket = sck;
                return generator.async_call((Action<socket_result> callback) => async_accept(sck, callback), _lostHandler.handler);
            }

            public Task unsafe_accept(async_result_wrap<socket_result> res, socket_tcp sck)
            {
                return generator.unsafe_async_call(res, (Action<socket_result> callback) => async_accept(sck, callback));
            }
        }
    }

    struct pipe_same_handler
    {
        public ArraySegment<byte> buff;
        public GCHandle pinnedObj;
        public Action<socket_result> callback;
        public AsyncCallback handler;
    }

#if !NETCORE
    public class socket_serial : socket
    {
        SerialPort _socket;
        pipe_same_handler _readSameHandler;
        pipe_same_handler _writeSameHandler;

        public socket_serial(string portName, int baudRate = 9600, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
        {
            _socket = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
            _readSameHandler.pinnedObj = default;
            _readSameHandler.callback = null;
            _readSameHandler.handler = delegate (IAsyncResult ar)
            {
                Action<socket_result> callback = _readSameHandler.callback;
                _readSameHandler.callback = null;
                try
                {
                    int size = _socket.BaseStream.EndRead(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _writeSameHandler.pinnedObj = default;
            _writeSameHandler.callback = null;
            _writeSameHandler.handler = delegate (IAsyncResult ar)
            {
                ArraySegment<byte> buff = _writeSameHandler.buff;
                Action<socket_result> callback = _writeSameHandler.callback;
                _writeSameHandler.buff = default(ArraySegment<byte>);
                _writeSameHandler.callback = null;
                try
                {
                    _socket.BaseStream.EndWrite(ar);
                    functional.catch_invoke(callback, new socket_result(true, buff.Count));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
        }

        public SerialPort socket
        {
            get
            {
                return _socket;
            }
        }

        public bool open()
        {
            try
            {
                _socket.Open();
                return true;
            }
            catch (System.Exception) { }
            return false;
        }

        public override void close()
        {
            try
            {
                _socket.Close();
            }
            catch (System.Exception) { }
        }

        public override void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            try
            {
                Debug.Assert(null == _readSameHandler.callback, "重入的 read 操作!");
                _readSameHandler.callback = callback;
                _socket.BaseStream.BeginRead(buff.Array, buff.Offset, buff.Count, _readSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            try
            {
                Debug.Assert(null == _writeSameHandler.callback, "重入的 write 操作!");
                _writeSameHandler.buff = buff;
                _writeSameHandler.callback = callback;
                _socket.BaseStream.BeginWrite(buff.Array, buff.Offset, buff.Count, _writeSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.buff = default(ArraySegment<byte>);
                _writeSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public void clear_in_buffer()
        {
            try
            {
                _socket.DiscardInBuffer();
            }
            catch (System.Exception) { }
        }

        public void clear_out_buffer()
        {
            try
            {
                _socket.DiscardOutBuffer();
            }
            catch (System.Exception) { }
        }
    }
#endif

    public abstract class socket_pipe : socket
    {
        protected PipeStream _socket;
        pipe_same_handler _readSameHandler;
        pipe_same_handler _writeSameHandler;

        protected socket_pipe()
        {
            _readSameHandler.pinnedObj = default;
            _readSameHandler.callback = null;
            _readSameHandler.handler = delegate (IAsyncResult ar)
            {
                Action<socket_result> callback = _readSameHandler.callback;
                _readSameHandler.callback = null;
                try
                {
                    int size = _socket.EndRead(ar);
                    functional.catch_invoke(callback, new socket_result(true, size));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
            _writeSameHandler.pinnedObj = default;
            _writeSameHandler.callback = null;
            _writeSameHandler.handler = delegate (IAsyncResult ar)
            {
                ArraySegment<byte> buff = _writeSameHandler.buff;
                Action<socket_result> callback = _writeSameHandler.callback;
                _writeSameHandler.buff = default(ArraySegment<byte>);
                _writeSameHandler.callback = null;
                try
                {
                    _socket.EndWrite(ar);
                    functional.catch_invoke(callback, new socket_result(true, buff.Count));
                }
                catch (System.Exception ec)
                {
                    functional.catch_invoke(callback, new socket_result(false, 0, ec));
                }
            };
        }

        public override void async_read_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            try
            {
                Debug.Assert(null == _readSameHandler.callback, "重入的 read 操作!");
                _readSameHandler.callback = callback;
                _socket.BeginRead(buff.Array, buff.Offset, buff.Count, _readSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _readSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }

        public override void async_write_same(ArraySegment<byte> buff, Action<socket_result> callback)
        {
            try
            {
                Debug.Assert(null == _writeSameHandler.callback, "重入的 write 操作!");
                _writeSameHandler.buff = buff;
                _writeSameHandler.callback = callback;
                _socket.BeginWrite(buff.Array, buff.Offset, buff.Count, _writeSameHandler.handler, null);
            }
            catch (System.Exception ec)
            {
                close();
                _writeSameHandler.buff = default(ArraySegment<byte>);
                _writeSameHandler.callback = null;
                functional.catch_invoke(callback, new socket_result(false, 0, ec));
            }
        }
    }

    public class socket_pipe_server : socket_pipe
    {
        readonly string _pipeName;

        public socket_pipe_server(string pipeName, int inBufferSize = 4 * 1024, int outBufferSize = 4 * 1024)
        {
            _pipeName = pipeName;
            _socket = new NamedPipeServerStream("CsGo_" + pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, inBufferSize, outBufferSize);
        }

        public NamedPipeServerStream socket
        {
            get
            {
                return (NamedPipeServerStream)_socket;
            }
        }

        public override void close()
        {
            try
            {
                ((NamedPipeServerStream)_socket).Disconnect();
            }
            catch (System.Exception) { }
            try
            {
                _socket.Close();
            }
            catch (System.Exception) { }
        }

        public async Task<bool> wait_connection(int ms = -1)
        {
            if (_socket.IsConnected)
            {
                return true;
            }
            bool overtime = false;
            async_timer waitTimeout = null;
            if (ms >= 0)
            {
                waitTimeout = new async_timer(generator.self_strand());
                waitTimeout.timeout(ms, delegate ()
                {
                    overtime = true;
                    try
                    {
                        NamedPipeClientStream timedPipe = new NamedPipeClientStream(".", "CsGo_" + _pipeName);
                        timedPipe.Connect(0);
                        timedPipe.Close();
                    }
                    catch (System.Exception) { }
                });
            }
            try
            {
                await generator.send_task(() => ((NamedPipeServerStream)_socket).WaitForConnection());
            }
            catch (System.Exception)
            {
                waitTimeout?.advance();
                close();
                return false;
            }
            if (overtime)
            {
                close();
            }
            waitTimeout?.cancel();
            return !overtime;
        }
    }

    public class socket_pipe_client : socket_pipe
    {
        public socket_pipe_client(string pipeName, string serverName = ".")
        {
            _socket = new NamedPipeClientStream(serverName, "CsGo_" + pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
        }

        public NamedPipeClientStream socket
        {
            get
            {
                return (NamedPipeClientStream)_socket;
            }
        }

        public override void close()
        {
            try
            {
                _socket.Close();
            }
            catch (System.Exception) { }
        }

        public bool try_connect(out bool closed)
        {
            closed = false;
            if (_socket.IsConnected)
            {
                return true;
            }
            try
            {
                ((NamedPipeClientStream)_socket).Connect(0);
                return true;
            }
            catch (System.TimeoutException) { }
            catch (System.Exception)
            {
                closed = true;
            }
            return false;
        }

        public async Task<bool> connect(int ms = -1)
        {
            if (0 == ms)
            {
                return try_connect(out bool _);
            }
            long beginTick = system_tick.get_tick_us();
            while (!try_connect(out bool closed))
            {
                if (closed)
                {
                    return false;
                }
                if (ms > 0 && system_tick.get_tick_us() - beginTick >= (long)ms * 1000)
                {
                    return false;
                }
                await generator.sleep(1);
            }
            return true;
        }
    }
}
